package controllers

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path"
	"strconv"
	"time"

	//"fmt"

	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"github.com/github-user/TokTik/models"
	"gopkg.in/mgo.v2/bson"
)

func GetVideos(c *gin.Context) {
	//session := sessions.Default(c)
	//v := session.Get("sessionid")
	var Videos []models.Video
	var Videosres []models.VideoRes
	models.FindAll(db, "Video", nil, nil, &Videos)

	for _, value := range Videos {
		var Video models.VideoRes
		Video.Vid = value.Vid
		Video.Title = value.Title
		Video.PublisherID = value.PublisherID
		Video.PublishedTime = value.PublishedTime
		Video.Comments = value.Comments
		Video.URL = value.URL
		Video.Image = value.Image

		var likers []string
		for _, va := range value.Likes {
			var liker models.User
			models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(va.LikerId)}, nil, &liker)
			likers = append(likers, liker.Info.Name)
		}
		Video.LikeSum = strconv.Itoa(len(likers))
		Video.CommentSum = strconv.Itoa(len(value.Comments))
		var user models.User
		models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(Video.PublisherID)}, nil, &user)
		Video.PublisherName = user.Info.Name
		Video.LikeNames = likers
		Videosres = append(Videosres, Video)
	}
	//c.Find(bson.M{"tags": bson.M{"$in": []string{"a"}}}).All(&articles)
	//models.FindAll(db, "Video", bson.M{"Friends": bson.M{"$in": []string{v.(string)}}}, nil, &Videos)
	c.JSON(http.StatusOK, &Response{
		Code:    200,
		Type:    "success",
		Message: Videosres,
	})
}

func GetPage(c *gin.Context) {
	page, _ := strconv.Atoi(c.Query("page"))
	eachPage, _ := strconv.Atoi(c.Query("eachPage"))
	var Videos []models.Video
	var Videosres []models.VideoRes

	models.FindByPage(db, "Video", (page-1)*eachPage, eachPage, nil, nil, &Videos)

	for _, value := range Videos {
		var Video models.VideoRes
		Video.Vid = value.Vid
		Video.Title = value.Title
		Video.PublisherID = value.PublisherID
		Video.PublishedTime = value.PublishedTime
		Video.Comments = value.Comments
		Video.URL = value.URL
		Video.Image = value.Image

		var likers []string
		for _, va := range value.Likes {
			var liker models.User
			models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(va.LikerId)}, nil, &liker)
			likers = append(likers, liker.Info.Name)
		}
		Video.LikeSum = strconv.Itoa(len(likers))
		Video.CommentSum = strconv.Itoa(len(value.Comments))
		var user models.User
		models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(Video.PublisherID)}, nil, &user)
		Video.PublisherName = user.Info.Name
		Video.LikeNames = likers
		Videosres = append(Videosres, Video)
	}

	c.JSON(http.StatusOK, &Response{
		Code:    200,
		Type:    "success",
		Message: Videosres,
	})
}

func GetUserVideos(c *gin.Context) {
	//session := sessions.Default(c)
	//v := session.Get("sessionid")
	var Videos []models.Video
	var Videosres []models.VideoRes

	models.FindAll(db, "Video", bson.M{"publisherId": c.Param("fid")}, nil, &Videos)

	for _, value := range Videos {
		var Video models.VideoRes
		Video.Vid = value.Vid
		Video.Title = value.Title
		Video.PublisherID = value.PublisherID
		Video.PublishedTime = value.PublishedTime
		Video.Comments = value.Comments
		Video.URL = value.URL
		Video.Image = value.Image
		for _, vb := range Video.Comments {
			var liker models.User
			models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(vb.PublisherId)}, nil, &liker)
			vb.PublisherName = liker.Info.Name

		}
		var likers []string
		for _, va := range value.Likes {
			var liker models.User
			models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(va.LikerId)}, nil, &liker)
			likers = append(likers, liker.Info.Name)
		}
		Video.LikeNames = likers
		var user models.User
		models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(Video.PublisherID)}, nil, &user)
		Video.PublisherName = user.Info.Name
		Videosres = append(Videosres, Video)
	}
	c.JSON(http.StatusOK, &Response{
		Code:    200,
		Type:    "success",
		Message: Videosres,
	})
}

//发表一条评论
func AddComment(c *gin.Context) {
	session := sessions.Default(c)
	v := session.Get("sessionid")

	var commentreq models.CommentReq
	var comment models.Comment
	json.NewDecoder(c.Request.Body).Decode(&commentreq)

	var Video models.Video

	models.FindOne(db, "Video", bson.M{"_id": bson.ObjectIdHex(commentreq.VideoId)}, nil, &Video)
	if Video.Vid == "" {
		c.JSON(http.StatusOK, &Response{
			Code:    400,
			Type:    "fail",
			Message: "Video does not exist",
		})
		return
	}
	comment.Cid = bson.NewObjectId()
	comment.Content = commentreq.Content
	comment.PublisherId = v.(string)
	var commenter models.User
	models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(v.(string))}, nil, &commenter)
	comment.PublisherName = commenter.Info.Name
	timeUnix := time.Now().Unix() //已知的时间戳
	comment.PublishedTime = strconv.FormatInt(timeUnix, 10)
	models.Update(db, "Video", bson.M{"_id": bson.ObjectIdHex(commentreq.VideoId)}, bson.M{"$push": bson.M{"comments": comment}})
	c.JSON(http.StatusOK, &Response{
		Code:    200,
		Type:    "success",
		Message: "",
	})
}

func AddLike(c *gin.Context) {
	session := sessions.Default(c)
	v := session.Get("sessionid")

	var likereq models.LikeReq
	var like models.Like
	json.NewDecoder(c.Request.Body).Decode(&likereq)

	var Video models.Video
	models.FindOne(db, "Video", bson.M{"_id": bson.ObjectIdHex(likereq.VideoId)}, nil, &Video)
	if Video.Vid == "" {
		c.JSON(http.StatusOK, &Response{
			Code:    400,
			Type:    "fail",
			Message: "Video does not exist",
		})
		return
	}

	like.Lid = bson.NewObjectId()
	like.LikerId = v.(string)
	for _, value := range Video.Likes {
		if value.LikerId == v.(string) {
			c.JSON(http.StatusOK, &Response{
				Code:    400,
				Type:    "fail",
				Message: "like has exist",
			})
			return
		}
	}
	models.Update(db, "Video", bson.M{"_id": bson.ObjectIdHex(likereq.VideoId)}, bson.M{"$push": bson.M{"likes": like}})

	c.JSON(http.StatusOK, &Response{
		Code:    200,
		Type:    "success",
		Message: "",
	})
}

func PublishVideo(c *gin.Context) {
	session := sessions.Default(c)
	v := session.Get("sessionid")

	switch c.Request.Method {
	//POST takes the uploaded file(s) and saves it to disk.
	case "POST":
		//parse the multipart form in the request
		err := c.Request.ParseMultipartForm(100000)
		if err != nil {
			http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
			return
		}
		m := c.Request.MultipartForm
		fmt.Println(c.PostForm("title"))
		img := m.File["image"]
		files := m.File["uploadfile"]
		var imgurl string

		for i, _ := range img {
			//for each fileheader, get a handle to the actual file
			file, err := img[i].Open()
			defer file.Close()
			if err != nil {
				http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
				return
			}
			fmt.Println("-----33----", img[i].Filename)
			datafile := make([]byte, img[i].Size)
			hash := md5.New()
			hash.Write(datafile)
			sum := hash.Sum(nil)
			toString := hex.EncodeToString(sum)
			fmt.Println(toString)
			fmt.Println(path.Ext(img[i].Filename))

			//create destination file making sure the path is writeable.
			dst, err := os.Create("./upload/" + toString + path.Ext(img[i].Filename))
			imgurl = toString + path.Ext(img[i].Filename)

			if err != nil {
				fmt.Println("err", err)
			}
			defer dst.Close()
			if err != nil {
				fmt.Println("---------------")
				http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
				c.JSON(http.StatusOK, &Response{
					Code:    400,
					Type:    "fail",
					Message: "",
				})
				return
			}
			//copy the uploaded file to the destination file
			if _, err := io.Copy(dst, file); err != nil {
				http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
				c.JSON(http.StatusOK, &Response{
					Code:    400,
					Type:    "fail",
					Message: "",
				})
				return
			}
		}

		for i, _ := range files {
			//for each fileheader, get a handle to the actual file
			file, err := files[i].Open()
			defer file.Close()
			if err != nil {
				http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
				return
			}
			fmt.Println("-----33----", files[i].Filename)
			datafile := make([]byte, files[i].Size)
			hash := md5.New()
			hash.Write(datafile)
			sum := hash.Sum(nil)
			toString := hex.EncodeToString(sum)
			fmt.Println(toString)
			fmt.Println(path.Ext(files[i].Filename))

			var video models.Video
			video.Vid = bson.NewObjectId()
			video.Title = c.PostForm("title")
			video.PublisherID = v.(string)
			timeUnix := time.Now().Unix() //已知的时间戳
			str := strconv.FormatInt(timeUnix, 10)
			video.PublishedTime = str

			//create destination file making sure the path is writeable.
			dst, err := os.Create("./upload/" + toString + path.Ext(files[i].Filename))
			video.URL = toString + path.Ext(files[i].Filename)
			video.Image = imgurl
			models.Insert(db, "Video", video)
			if err != nil {
				fmt.Println("err", err)
			}
			defer dst.Close()
			if err != nil {
				fmt.Println("---------------")
				http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
				c.JSON(http.StatusOK, &Response{
					Code:    400,
					Type:    "fail",
					Message: "",
				})
				return
			}
			//copy the uploaded file to the destination file
			if _, err := io.Copy(dst, file); err != nil {
				http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
				c.JSON(http.StatusOK, &Response{
					Code:    400,
					Type:    "fail",
					Message: "",
				})
				return
			}

			c.JSON(http.StatusOK, &Response{
				Code:    200,
				Type:    "success",
				Message: "",
			})
		}

	default:
		c.Writer.WriteHeader(http.StatusMethodNotAllowed)
	}
}

func StarVideo(c *gin.Context) {
	session := sessions.Default(c)
	v := session.Get("sessionid")
	var starreq models.LikeReq
	var Video models.Video
	var user models.User
	json.NewDecoder(c.Request.Body).Decode(&starreq)
	models.FindOne(db, "Video", bson.M{"_id": bson.ObjectIdHex(starreq.VideoId)}, nil, &Video)
	models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(v.(string))}, nil, &user)
	for _, value := range user.Star {
		if value.Vid.Hex() == starreq.VideoId {
			c.JSON(http.StatusOK, &Response{
				Code:    400,
				Type:    "fail",
				Message: "star has exist",
			})
			return
		}
	}
	models.Update(db, "user", bson.M{"_id": bson.ObjectIdHex(v.(string))}, bson.M{"$push": bson.M{"star": Video}})

	c.JSON(http.StatusOK, &Response{
		Code:    200,
		Type:    "success",
		Message: "",
	})
}

func GetStar(c *gin.Context) {
	session := sessions.Default(c)
	v := session.Get("sessionid")
	var Videosres []models.VideoRes
	var user models.User
	models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(v.(string))}, nil, &user)

	for _, value := range user.Star {
		var Video models.VideoRes
		Video.Vid = value.Vid
		Video.Title = value.Title
		Video.PublisherID = value.PublisherID
		Video.PublishedTime = value.PublishedTime
		Video.Comments = value.Comments
		Video.URL = value.URL
		Video.Image = value.Image
		for _, vb := range Video.Comments {
			var liker models.User
			models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(vb.PublisherId)}, nil, &liker)
			vb.PublisherName = liker.Info.Name

		}
		var likers []string
		for _, va := range value.Likes {
			var liker models.User
			models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(va.LikerId)}, nil, &liker)
			likers = append(likers, liker.Info.Name)
		}
		Video.LikeNames = likers
		var user models.User
		models.FindOne(db, "user", bson.M{"_id": bson.ObjectIdHex(Video.PublisherID)}, nil, &user)
		Video.PublisherName = user.Info.Name
		Videosres = append(Videosres, Video)
	}
	c.JSON(http.StatusOK, &Response{
		Code:    200,
		Type:    "success",
		Message: Videosres,
	})
}

func DeleteStar(c *gin.Context) {
	session := sessions.Default(c)
	v := session.Get("sessionid")
	models.Update(db, "user", bson.M{"_id": bson.ObjectIdHex(v.(string))}, bson.M{"$pull": bson.M{"star": bson.M{"_id": bson.ObjectIdHex(c.Param("id"))}}})
	c.JSON(http.StatusOK, &Response{
		Code:    200,
		Type:    "success",
		Message: "",
	})
}
